package org.moore.utils;

import org.moore.model.Block;
import org.moore.model.Map;

import javax.swing.*;
import java.util.ArrayList;
import java.util.Random;

// 消除物模型类
public class BlockUtils {
    // 判断是否是5消的下一步
    private static int isScore = 0;
    private static int isScore1 = 0;
    private static int count = 0;
    private static int count1 = 0;
    // 交换消除物的方法
    public static void blockExchange(int x1, int y1, int x2, int y2) {
        // 设置第一次点击的消除物被选中为未选中
        Map.getMap()[y1][x1].setSelected(false);
        // 交换消除物的行和列
        // 根据两个消除物的位置一点点交换坐标以达成动画效果
        if (x1 == x2 && Map.getMap()[x1][y1].getBlockType() != 0 && Map.getMap()[x2][y2].getBlockType() != 0){
            for (int i = 0; i < 70; i++){
                if (y1 > y2){
                    Map.getMap()[x1][y1].setX(Map.getMap()[x1][y1].getX()-1);
                    Map.getMap()[x2][y2].setX(Map.getMap()[x2][y2].getX()+1);
                }
                if (y1 < y2) {
                    Map.getMap()[x1][y1].setX(Map.getMap()[x1][y1].getX()+1);
                    Map.getMap()[x2][y2].setX(Map.getMap()[x2][y2].getX()-1);
                }
                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        if (y1 == y2 && Map.getMap()[x1][y1].getBlockType() != 0 && Map.getMap()[x2][y2].getBlockType() != 0){
            for (int i = 0; i < 70; i++) {
                if (x1 > x2){
                    Map.getMap()[x1][y1].setY(Map.getMap()[x1][y1].getY()-1);
                    Map.getMap()[x2][y2].setY(Map.getMap()[x2][y2].getY()+1);
                }
                if (x1 < x2) {
                    Map.getMap()[x1][y1].setY(Map.getMap()[x1][y1].getY()+1);
                    Map.getMap()[x2][y2].setY(Map.getMap()[x2][y2].getY()-1);
                }
                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }

        // 交换消除物的数组
        if (Map.getMap()[x1][y1].getBlockType() != 0 && Map.getMap()[x2][y2].getBlockType() != 0) {
            Block temp = Map.getMap()[x1][y1];
            Map.getMap()[x1][y1] = Map.getMap()[x2][y2];
            Map.getMap()[x2][y2] = temp;
        }
    }

    // 获取消除物是否可消除的方法
    public static boolean findBlocksEliminated() {
        // 使用布尔值用于是否有可消除物
        boolean isTrue = false;
        if (isScore == 3) {
            isScore = 0;
        }
        if (isScore1 == 3) {
            isScore1 = 0;
        }
        for (int i = 0; i <= Map.getMap().length -1; i++) {
            for (int j = 0; j <= Map.getMap()[0].length -1; j++) {
                // 判断同一列或同一行的消除物是否可消除
                Block block = Map.getMap()[i][j];
                // 如果为空则跳过
                if (block == null) {
                    continue;
                }
                if (Map.getMap()[i][j].getBlockType() != 0) {
                    // 判断每个消除物右边的消除物是否可消除
                    count = 0;
                    for (int k = 0; k < Map.getMap().length -j; k++) {
                        // 如果为空则跳出
                        if (Map.getMap()[i][j+k] == null) {
                            break;
                        }
                        // 如果类型相同则计数加1
                        if (Map.getMap()[i][j+k].getBlockType() == block.getBlockType()) {
                            count++;
                        } else {
                            // 否测跳出
                            break;
                        }
                    }
                    // 判断每个消除物下方的消除物是否可消除
                    count1 = 0;
                    for (int k = 0;k < Map.getMap()[0].length -i; k++) {
                        // 如果为空则跳出
                        if (Map.getMap()[i+k][j] == null) {
                            break;
                        }
                        // 如果类型相同则计数加1
                        if (Map.getMap()[i+k][j].getBlockType() == block.getBlockType()) {
                            count1++;
                        } else {
                            // 否测跳出
                            break;
                        }
                    }
                    // 如果计数大于两个则将每个可消除物设置为可消除
                    if (count > 2) {
                        for (int k = 0; k < count; k++){
                            if (Map.getMap()[i][j + k] != null) {
                                Map.getMap()[i][j+k].setEliminated(true);
                            }
                        }
                        // 设置为有可消除物
                        isTrue = true;
                    }
                    // 如果计数大于两个则将每个可消除物设置为可消除
                    if (count1 > 2) {
                        for (int k = 0; k < count1; k++){
                            if (Map.getMap()[i + k][j] != null) {
                                Map.getMap()[i+k][j].setEliminated(true);
                            }
                        }
                        // 设置为有可消除物
                        isTrue = true;
                    }
                    // 时间/步数奖励
                    if (count == 5){
                        isScore++;
                    } else if (count1 == 5) {
                        isScore1++;
                    }
                    if (count == 4 || count1 == 4) {
                        if (Map.isMapType() == 1) {
                            Data.STEPS++;
                        } else if (Map.isMapType() == 2){
                            Countdown.setSeconds(Countdown.getSeconds()+2);
                        }
                    }
                }
            }
        }
        // 返回布尔值
        return isTrue;
    }

    // 使消除物消除的方法
    public static void blockIsEliminated() {
        for (int i = 0; i < Map.getMap().length; i++) {
            for (int j = 0; j < Map.getMap()[0].length; j++) {
                // 如果该位置不为空且消除物被设置为可消除则设置为空以消除
                if (Map.getMap()[i][j] != null && Map.getMap()[i][j].getBlockType() != 0) {
                    if (Map.getMap()[i][j].isEliminated()) {
                        Map.getMap()[i][j] = null;
                        if (isScore != 2 || isScore1 != 2) {
                            Data.SCORE += 5;
                        }
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
        }
        // 添加分数
        if (isScore == 2) {
            Data.SCORE += count *2;
        } else if (isScore1 == 2) {
            Data.SCORE += count1 *2;
        }
        isScore++;
        isScore1++;
    }

    // 使消除物下落和生成的方法
    public static void blockGenerate(){
        for (int i = Map.getMap().length - 1; i >= 0; i--) {
            // 获取已消除的消除物的列
            while (true) {
                ArrayList<Integer> num = new ArrayList<>();
                for (int j = Map.getMap().length - 1; j >= 0; j--) {
                    if (Map.getMap()[i][j] == null) {
                        num.add(j);
                    }
                }
                // 当集合非空才运行
                if (!num.isEmpty()) {
                    // 使消除物坐标下落
                    for (int j = 0; j < 70; j++) {
                        for (int number : num) {
                            for (int l = i - 1; l >= 0; l--) {
                                if (Map.getMap()[l][number] != null && Map.getMap()[l][number].getBlockType() != 0) {
                                    Map.getMap()[l][number].setY(Map.getMap()[l][number].getY() + 1);
                                }
                            }
                            try {
                                Thread.sleep(2);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                        }
                    }
                    // 根据关卡类型运行不同方法
                    if (Map.getLevel() == 1){ // 方形
                        // 使消除物数组位置下落
                        for (int number : num) {
                            for (int k = i; k > 0; k--) {
                                Map.getMap()[k][number] = Map.getMap()[k - 1][number];
                            }
                            // 生成新的消除物
                            Random random = new Random();
                            int n = random.nextInt(Map.getMaxBlockType()) + 1;
                            Map.getMap()[0][number] = new Block(0, 0, number, n, new ImageIcon("Image/IMG " + n + ".png").getImage());
                            Map.getMap()[0][number].setX(Data.START_X + number * Data.GRID);
                            Map.getMap()[0][number].setY(Data.START_Y);
                        }
                    } else if (Map.getLevel() == 2){ // 菱形
                        // 使消除物数组位置下落
                        for (int numberCol : num) {
                            // 找到每列中最高的障碍物
                            int highestObstacle = -1;
                            for (int k = 0; k < Map.getRows(); k++) {
                                if (Map.getMap()[k][numberCol] != null && Map.getMap()[k][numberCol].getBlockType() != 0) {
                                    highestObstacle = k;
                                    break;
                                }
                            }
                            // 在最高的障碍物下方生成新的消除物
                            for (int k = i; k > highestObstacle; k--) {
                                Map.getMap()[k][numberCol] = Map.getMap()[k - 1][numberCol];
                            }
                            // 生成新的消除物
                            Random random = new Random();
                            int n = random.nextInt(Map.getMaxBlockType()) + 1;
                            int numberRow = 0;
                            switch (numberCol) {
                                case 0:
                                case 8:
                                    numberRow = 4;
                                    break;
                                case 1:
                                case 7:
                                    numberRow = 3;
                                    break;
                                case 2:
                                case 6:
                                    numberRow = 2;
                                    break;
                                case 3:
                                case 5:
                                    numberRow = 1;
                                    break;
                                case 4:
                                    break;
                            }
                            Map.getMap()[numberRow][numberCol] = new Block(0, numberRow, numberCol, n, new ImageIcon("Image/IMG " + n + ".png").getImage());
                            Map.getMap()[numberRow][numberCol].setX(Data.START_X + numberCol * Data.GRID);
                            Map.getMap()[numberRow][numberCol].setY(Data.START_Y + numberRow * Data.GRID);
                        }
                    } else if (Map.getLevel() == 3) { // 心形
                        // 使消除物数组位置下落
                        for (int numberCol : num) {
                            // 找到每列中最高的障碍物
                            int highestObstacle = -1;
                            for (int k = 0; k < Map.getRows(); k++) {
                                if (Map.getMap()[k][numberCol] != null && Map.getHeartShape()[k][numberCol] == 1) {
                                    highestObstacle = k;
                                    break;
                                }
                            }
                            // 在最高的障碍物下方生成新的消除物
                            for (int k = i; k > highestObstacle; k--) {
                                Map.getMap()[k][numberCol] = Map.getMap()[k - 1][numberCol];
                            }
                            // 生成新的消除物
                            Random random = new Random();
                            int n = random.nextInt(Map.getMaxBlockType()) + 1;
                            int numberRow = 0;
                            for (int k = 0; k < Map.getHeartShape().length; k++) {
                                if (Map.getHeartShape()[k][numberCol] == 1) {
                                    numberRow = k;
                                    break;
                                }
                            }
                            Map.getMap()[numberRow][numberCol] = new Block(0, numberRow, numberCol, n, new ImageIcon("Image/IMG " + n + ".png").getImage());
                            Map.getMap()[numberRow][numberCol].setX(Data.START_X + numberCol * Data.GRID);
                            Map.getMap()[numberRow][numberCol].setY(Data.START_Y + numberRow * Data.GRID);
                        }
                    }
                } else {
                    break;
                }
            }
        }
        for (int i = 0; i < Map.getMap().length; i++) {
            for (int j = 0; j < Map.getMap().length; j++) {
                Map.getMap()[i][j].setSelected(false);
            }
        }
    }

    // 提示有可消除物的方法
    public static boolean blockTip() {
        boolean isTrue = false;
        Block[][] type = new Block[Map.getMap().length][Map.getMap()[0].length];
        for (int i = 0;i < Map.getMap().length -1; i++){
            for (int j = 0; j < Map.getMap()[0].length -1; j++) {
                if (Map.getMap()[i][j].getBlockType() != 0) {
                    type[i][j] =  new Block(Map.getMap()[i][j].getBlockType());
                }
            }
        }
        for (int i = 0;i < Map.getMap().length -1 ;i++) {
            for (int j = 0; j < Map.getMap()[0].length-1; j++) {
                Block typeNum = type[i][j];
                if (Map.getMap()[i][j].getBlockType() != 0) {
                    // 向上判断
                    if (i-1 >= 0){
                        Block typeNum1 = type[i - 1][j];
                        type[i][j] = typeNum1;
                        type[i - 1][j] = typeNum;
                        if (findBlocksTip(type)) {
                            type[i][j] = typeNum;
                            type[i - 1][j] = typeNum1;
                            Map.getMap()[i][j].setSelected(true);
                            Map.getMap()[i-1][j].setSelected(true);
                            return true;
                        } else {
                            type[i][j] = typeNum;
                            type[i - 1][j] = typeNum1;
                        }
                    }
                    // 向下判断
                    if (i+1 <= Map.getMap()[0].length){
                        Block typeNum1 = type[i + 1][j];
                        type[i][j] = typeNum1;
                        type[i + 1][j] = typeNum;
                        if (findBlocksTip(type)) {
                            type[i][j] = typeNum;
                            type[i + 1][j] = typeNum1;
                            Map.getMap()[i][j].setSelected(true);
                            Map.getMap()[i+1][j].setSelected(true);
                            return true;
                        } else {
                            type[i][j] = typeNum;
                            type[i + 1][j] = typeNum1;
                        }
                    }
                    // 向左判断
                    if (j-1 >= 0){
                        Block typeNum1 = type[i][j - 1];
                        type[i][j] = typeNum1;
                        type[i][j - 1] = typeNum;
                        if (findBlocksTip(type)) {
                            type[i][j] = typeNum;
                            type[i][j - 1] = typeNum1;
                            Map.getMap()[i][j].setSelected(true);
                            Map.getMap()[i][j-1].setSelected(true);
                            return true;
                        } else {
                            type[i][j] = typeNum;
                            type[i][j - 1] = typeNum1;
                        }
                    }
                    // 向右判断
                    if (j+1 <= Map.getMap().length){
                        Block
                                typeNum1 = type[i][j + 1];
                        type[i][j] = typeNum1;
                        type[i][j + 1] = typeNum;
                        if (findBlocksTip(type)) {
                            type[i][j] = typeNum;
                            type[i][j + 1] = typeNum1;
                            Map.getMap()[i][j].setSelected(true);
                            Map.getMap()[i][j+1].setSelected(true);
                            return true;
                        } else {
                            type[i][j] = typeNum;
                            type[i][j + 1] = typeNum1;
                        }
                    }
                }
            }
        }
        return isTrue;
    }

    // 获取消除物是否可消除的方法
    public static boolean findBlocksTip(Block[][] type) {
        // 使用布尔值用于是否有可消除物
        boolean isTrue = false;
        for (int i = 0; i <= type.length -1; i++) {
            for (int j = 0; j <= type[0].length -1; j++) {
                // 判断同一列或同一行的消除物是否可消除
                Block block = type[i][j];
                // 如果为空则跳过
                if (block == null) {
                    continue;
                }
                if (Map.getMap()[i][j].getBlockType() != 0) {
                    // 判断每个消除物右边的消除物是否可消除
                    int count = 0;
                    for (int k = 0; k < type.length -j; k++) {
                        // 如果为空则跳出
                        if (type[i][j+k] == null) {
                            break;
                        }
                        // 如果类型相同则计数加1
                        if (type[i][j+k].getBlockType() == block.getBlockType()) {
                            count++;
                        } else {
                            // 否测跳出
                            break;
                        }
                    }
                    // 判断每个消除物下方的消除物是否可消除
                    int count1 = 0;
                    for (int k = 0;k < type[0].length -i; k++) {
                        // 如果为空则跳出
                        if (type[i+k][j] == null) {
                            break;
                        }
                        // 如果类型相同则计数加1
                        if (type[i+k][j].getBlockType() == block.getBlockType()) {
                            count1++;
                        } else {
                            // 否测跳出
                            break;
                        }
                    }
                    // 如果计数大于两个则将每个可消除物设置为可消除
                    if (count > 2) {
                        // 设置为有可消除物
                        isTrue = true;
                    }
                    // 如果计数大于两个则将每个可消除物设置为可消除
                    if (count1 > 2) {
                        // 设置为有可消除物
                        isTrue = true;
                    }
                }
            }
        }
        // 返回布尔值
        return isTrue;
    }
}
